#ifndef SERIALDATAPARSER_HPP
#define SERIALDATAPARSER_HPP

#include <stdint.h>
#include <string.h>

#define MAX_PACKET_SIZE (64)

enum PARSE_STATE {
    PARSE_HEADER,
    PARSE_CMD,
    PARSE_LENGTH,
    PARSE_DATA,
    PARSE_CHECKSUM,
    PARSE_END
};

enum CMD {
    CMD_SUN_DATA = 0x01,
};

typedef struct {
    uint8_t cmd;
    uint8_t length;
    uint8_t data[MAX_PACKET_SIZE - 5];
    uint8_t checksum;
} SerialPacket;

typedef struct {
    uint8_t x;
    uint8_t y;
    uint8_t graySun;
    uint8_t grayBg;
} SunData;

class SerialDataParser {
public:
    SerialDataParser()
        : bufferIndex(0), currentState(0) {
        memset(&packet, 0, sizeof(SerialPacket));
    }

    bool parseData(uint8_t data) {
        switch (currentState) {
        case PARSE_HEADER: {
            if (data == 0x33) { // 起始字节
                bufferIndex = 0;
                currentState = PARSE_CMD;
            }
        } break;
        case PARSE_CMD: {
            packet.cmd = data;
            currentState = PARSE_LENGTH;
        } break;
        case PARSE_LENGTH: {
            packet.length = data;
            if (packet.length > MAX_PACKET_SIZE - 5) {
                reset();
            } else if (packet.length > 0) {
                currentState = PARSE_DATA;
            } else {
                currentState = PARSE_CHECKSUM;
            }
        } break;
        case PARSE_DATA: {
            packet.data[bufferIndex++] = data;
            if (bufferIndex == packet.length) {
                currentState = PARSE_CHECKSUM;
            }
        } break;
        case PARSE_CHECKSUM: {
            packet.checksum = data;
            if (calculateChecksum(packet) == packet.checksum) {
                currentState = PARSE_END;
                return true;
            } else {
                reset();
            }
        } break;
        case PARSE_END: {
            return true;
        } break;

        default:
            break;
        }
        return false;
    }

    const uint8_t getCmd() const {
        return packet.cmd;
    }

    const SerialPacket& getPacket() const {
        return packet;
    }

    template <typename T>
    bool getPacketData(T& data) const {
        if (sizeof(T) != packet.length) {
            return false;
        }
        memcpy(&data, packet.data, sizeof(T));
        return true;
    }

    void reset() {
        bufferIndex = 0;
        currentState = PARSE_HEADER;
        memset(&packet, 0, sizeof(SerialPacket));
    }

private:
    SerialPacket packet;
    int bufferIndex;
    int currentState;

    uint8_t calculateChecksum(const SerialPacket &packet) const {
        uint8_t checksum = 0;
        checksum += packet.cmd;
        checksum += packet.length;
        for (int i = 0; i < packet.length; ++i) {
            checksum += packet.data[i];
        }
        return checksum;
    }
};

#endif // SERIALDATAPARSER_HPP